#ifndef __STREAM_BUILDER_H__
#define __STREAM_BUILDER_H__ 1

#include <string>
#include <vector>

#include <sys/time.h>

#include "packet_source.h"
#include "stegio.h"
#include "properties_reader.h"

/**
 * @brief stream builder for guaranteed stream communication
 * @author mnutzinger, jwurzer
 */
class CStreamBuilder : public IPacketSource
{
public:
	CStreamBuilder(CPropertiesReader* pConfig, IStegIO* pStegIO);
	virtual ~CStreamBuilder();

	virtual NPacketSource::EPayloadInfo getPacket(void*& pPacket, unsigned int& pPacketLength,
			unsigned int pMaxLength);
	virtual void putPacket(void* pPacket, unsigned int pPacketLength);

private:
	class CPacket {
	public:
		unsigned int mId; // between 0 and 15, 16 means mData is unused
		unsigned int mLength;
		std::vector<unsigned char> mData;

		CPacket() :
				mId(CStreamBuilder::sMaxId),
				mLength(0),
				mData()
		{ }
	};

	class CParam {
	public:
		unsigned int mNextId; // between 0 and 15
		unsigned int mAck; // between 0 and 15
		CPacket** mPackets;
		unsigned int mPacketCount;

		CParam(unsigned int pPacketCount) :
			mNextId(0),
			mAck(0),
			mPackets(NULL),
			mPacketCount(pPacketCount)
		{
			mPackets = new CPacket*[mPacketCount];
			for (unsigned int i = 0; i < mPacketCount; i++) {
				mPackets[i] = new CPacket();
			}
		}

		virtual ~CParam()
		{
			for (unsigned int i = 0; i < mPacketCount; i++) {
				delete mPackets[i];
			}

			delete[] mPackets;
		}
	};

	class CSendParam : public CParam {
	public:
		timeval mLastTime;

		CSendParam(unsigned int pPacketCount) :
			CParam(pPacketCount),
			mByteBuffer(NULL),
			mByteBufferSize(0)
		{ }

		virtual ~CSendParam()
		{
			getByteBuffer(0);
		}

		/**
		 * create a packet as byte array from the specified packet id
		 *
		 * @param pPacket pointer to the byte array
		 * @param pPacketLength length of the packet
		 * @param pPacketId desired packet id (from mSendPackets)
		 */
		void createPacket(void*& pPacket, unsigned int& pPacketLength,
				unsigned int pPacketId);

		/**
		 * get a buffer of specific length
		 * @note a size of 0 frees the buffer
		 *
		 * @param pSize desired size
		 * @return pointer to the buffer
		 */
		unsigned char* getByteBuffer(unsigned int pSize);

	private:
		unsigned char* mByteBuffer;
		unsigned int mByteBufferSize;
	};

	class CRecvParam : public CParam {
	public:
		CRecvParam(unsigned int pPacketCount) :
			CParam(pPacketCount)
		{ }

		virtual ~CRecvParam()
		{ }
	};

	CStreamBuilder(const CStreamBuilder& );
	CStreamBuilder& operator=(const CStreamBuilder& );

	static const std::string sIniSectionName;
	static const unsigned int sMaxId;
	static const unsigned int sWindowSize;
	static const unsigned int sResizeInc;

	CPropertiesReader* mConfig;
	IStegIO* mStegIO;

	// ***************
	// send parameters
	// ***************

	CSendParam mSend;

	// ******************
	// receive parameters
	// ******************

	CRecvParam mRecv;
};

#endif // __STREAM_BUILDER_H__

